/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.subcommands;

import mosdi.fa.Alphabet;
import mosdi.util.Iupac;
import mosdi.util.IupacStringConstraints;
import mosdi.util.Log;
import mosdi.util.iterators.IupacPatternGenerator;
import mosdi.util.iterators.RandomStringGenerator;

public class IupacGenSubcommand extends Subcommand {

	@Override
	public String usage() {
		return
		super.usage()+" [options] <length>\n" +
		"Options:\n" +
		"  -m minimum number of 1-/2-/3-/4-valued letters, default: \"0,0,0,0\"\n" +
		"  -M maximum number of 1-/2-/3-/4-valued letters, default: \"<length>,0,0,0\"\n" +
		"  -c only output the number of strings, do not enumerate them\n" +
		"  -r omit strings that are lexicographically larger than their\n" +
		"     reverse complement\n" +
		"  -R <number>: print only <number> randomly choosen strings";
	}

	@Override
	public String description() {
		return "Enumerates IUPAC strings.";
	}

	@Override
	public String name() {
		return "iupac-gen";
	}

	@Override
	public int run(String[] args) {
		parseOptions(args, 1, "m:M:crR:");

		// Option dependencies
		exclusiveOptions("r", "c");
		exclusiveOptions("R", "P");
		exclusiveOptions("R", "c");
		exclusiveOptions("R", "a");

		// Mandatory arguments
		int length = getIntArgument(0);

		// Options
		int[] minFrequencies = {0,0,0,0};
		minFrequencies = getRangedIntTupleOption("m", 4, 0, length, minFrequencies);
		int[] maxFrequencies = {length,0,0,0};
		maxFrequencies = getRangedIntTupleOption("M", 4, 0, length, maxFrequencies);
		boolean count = getBooleanOption("c", false);
		boolean omitReverse = getBooleanOption("r", false);
		int randomStringCount = getPositiveIntOption("R", -1);

		if (randomStringCount>0) {
			// TODO: DO THIS SMARTER! e.g. implement skip() method in IupacStringGenerator
			// TODO: check, whether there are enough strings, otherwise this is an endless loop
			// TODO: check for duplicate strings
			IupacStringConstraints constraints = new IupacStringConstraints(minFrequencies, maxFrequencies);
			int n = 0;
			for (String s : new RandomStringGenerator(new Alphabet(constraints.getValidCharacters()), length)) {
				if (!constraints.check(s)) continue;
				if (omitReverse && (s.compareTo(Iupac.reverseComplementary(s))>0)) continue;
				Log.println(Log.Level.STANDARD, s);
				n+=1;
				if (n==randomStringCount) break;
			}
		} else {
			IupacStringConstraints constraints = new IupacStringConstraints(minFrequencies,maxFrequencies);
			IupacPatternGenerator sg = new IupacPatternGenerator(length, constraints);
			if (count) {
				Log.printf(Log.Level.STANDARD, "%d%n", constraints.validStringCount(length));
			} else {
				if (omitReverse) {
					for (int[] intString : sg) {
						String s = Alphabet.getIupacAlphabet().buildString(intString);
						if (s.compareTo(Iupac.reverseComplementary(s))<=0) {
							Log.println(Log.Level.STANDARD, s);
						}
					}
				} else {
					for (int[] intString : sg) {
						String s = Alphabet.getIupacAlphabet().buildString(intString);
						Log.println(Log.Level.STANDARD, s);
					}
				}
			}
		}
		return 0;
	}

}
